﻿/*
 * Created by SharpDevelop.
 * User: MyWife
 * Date: 7/26/2010
 * Time: 4:33 PM
 * 
 * To change this template use Tools | Options | Coding | Edit Standard Headers.
 */

using System;
using System.Drawing;
using System.Windows.Forms;
using popLib;
using System.ComponentModel;
using System.Text.RegularExpressions;
using System.Collections.Generic;
using System.IO;

namespace popLib.ExtensionClass
{
	/// <summary>
	/// Description of FormValidation.
	/// </summary>
	public class FormValidation
	{					
		ErrorProvider ERROR_PROVIDER;
		List<Control> CONTROL_TO_VALIDATE;
		bool IS_VALIDATED = true;
		Form FORM_TO_VALIDATE;
		
		public FormValidation(Form formToValidate)
		{
			FORM_TO_VALIDATE = formToValidate;			
			CONTROL_TO_VALIDATE = new List<Control>();
			ERROR_PROVIDER = new ErrorProvider();			
		}
		
		public bool Validate(){
			IS_VALIDATED = true;
			
			foreach(Control control in CONTROL_TO_VALIDATE ){
				control.Focus();
				FORM_TO_VALIDATE.Validate();
			}
			
			return IS_VALIDATED;
		}
		
		public void Invalidate(){
        	ERROR_PROVIDER.Clear();
        }
		
		#region ValidateGroupRadioButton
		/// <summary>
		/// Validate group of RadioButton that located in one container
		/// </summary>
		/// <param name="container">Container control could be Panel, FlowLayoutPanel, GroupBox</param>
		public void ValidateGroupRadioButton( Control container ){
			ValidateGroupRadioButton( container, null );
		}
		
		/// <summary>
		/// Validate group of RadioButton that located in one container
		/// </summary>
		/// <param name="container">Container control could be Panel, FlowLayoutPanel, GroupBox</param>
		/// <param name="message">Custom message if message is not null or blank</param>
		public void ValidateGroupRadioButton( Control container, string message ){
			CONTROL_TO_VALIDATE.Add( container );
			
			container.Validating += delegate(object sender, CancelEventArgs e) {
				Control senderControl = (Control)sender;
				
				int checkedCounter = 0;
				foreach( RadioButton item in senderControl.Controls ){
					if( item.Checked ) checkedCounter++;
				}
				
				if( checkedCounter < 1 ) {
					if( !StringLib.isValid(message) ) 
						message = ValidationMessage.Singleton().ValidateGroupRadioButton;
						
					ERROR_PROVIDER.SetError( senderControl, message );
					IS_VALIDATED = false;
				}else{
					ERROR_PROVIDER.SetError( senderControl, null );
				}
			};
		}
		#endregion
		
		#region ValidateGroupCheckBox
		/// <summary>
		/// Validate group of CheckBox that located in one container and specify total of CheckBox must be checked
		/// </summary>
		/// <param name="container">Container control could be Panel, FlowLayoutPanel, GroupBox</param>
		/// <param name="minimumChecked">Total checked box must be checked</param>
		public void ValidateGroupCheckBox( Control container, int minimumChecked ){
			ValidateGroupCheckBox( container, minimumChecked, null );
		}
		
		
		/// <summary>
		/// Validate group of CheckBox that located in one container and specify total of CheckBox must be checked
		/// </summary>
		/// <param name="container">Container control could be Panel, FlowLayoutPanel, GroupBox</param>
		/// <param name="minimumChecked">Total checked box must be checked</param>
		/// <param name="message">Custom message if message is not null or blank</param>
		public void ValidateGroupCheckBox( Control container, int minimumChecked, string message ){
			CONTROL_TO_VALIDATE.Add( container );
			
			container.Validating += delegate(object sender, CancelEventArgs e) {
				Control senderControl = (Control)sender;
				
				int checkedCounter = 0;
				foreach( CheckBox item in senderControl.Controls ){
					if( item.Checked ) checkedCounter++;
				}
				
				if( checkedCounter < minimumChecked ) {
					
					if( !StringLib.isValid(message) )
						message = ValidationMessage.Singleton().ValidateGroupCheckBox;
					message = message.Replace( "[MIN]", minimumChecked+"" );
					
					ERROR_PROVIDER.SetError( senderControl, message );
					IS_VALIDATED = false;
				}else{
					ERROR_PROVIDER.SetError( senderControl, null );
				}
			};
		}
		#endregion
		
		#region ValidateCheckedListBox
		/// <summary>
		/// Validate CheckedListBox and specify total of items must be checked
		/// </summary>
		/// <param name="control">CheckedListBox to validate</param>
		/// <param name="minimumChoice">Total of items must be checked</param>
		public void ValidateCheckedListBox( CheckedListBox control, int minimumChoice ){
			ValidateCheckedListBox( control, minimumChoice, null );
		}
		
		/// <summary>
		/// Validate CheckedListBox and specify total of items must be checked
		/// </summary>
		/// <param name="control">CheckedListBox to validate</param>
		/// <param name="minimumChoice">Total of items must be checked</param>
		/// <param name="message">Custom message if message is not null or blank</param>
		public void ValidateCheckedListBox( CheckedListBox control, int minimumChoice, string message ){
			CONTROL_TO_VALIDATE.Add( control );
			
			control.Validating += delegate(object sender, CancelEventArgs e) {
				CheckedListBox senderControl = (CheckedListBox)sender;
				if( senderControl.CheckedIndices.Count < minimumChoice ) {
					
					if( !StringLib.isValid(message) )
						message = ValidationMessage.Singleton().ValidateCheckedListBox;
					message = message.Replace( "[MIN]", minimumChoice+"" );
					
					ERROR_PROVIDER.SetError( senderControl, message );
					IS_VALIDATED = false;
				}else{
					ERROR_PROVIDER.SetError( senderControl, null );
				}
			};
		}
		#endregion
				
		#region ValidateListBox
		/// <summary>
		/// Validate ListBox by specifing total items must be selected
		/// </summary>
		/// <param name="control">ListBox to validate</param>
		/// <param name="minimumSelection">Total of item must be selected</param>
		public void ValidateListBox( ListBox control, int minimumSelection ){
			ValidateListBox( control, minimumSelection, null );
		}
		
		/// <summary>
		/// Validate ListBox by specifing total items must be selected
		/// </summary>
		/// <param name="control">ListBox to validate</param>
		/// <param name="minimumSelection">Total of item must be selected</param>
		/// <param name="message">Custom message if message is not null or blank</param>
		public void ValidateListBox( ListBox control, int minimumSelection, string message ){
			CONTROL_TO_VALIDATE.Add( control );
			
			if( minimumSelection > 1 )
				control.SelectionMode = SelectionMode.MultiExtended;
			
			control.Validating += delegate(object sender, CancelEventArgs e) {
				ListBox senderControl = (ListBox)sender;
				if( senderControl.SelectedIndices.Count < minimumSelection ) {
					
					if( !StringLib.isValid(message) )
						message = ValidationMessage.Singleton().ValidateListBox;
					message = message.Replace( "[MIN]", minimumSelection+"" );
					
					ERROR_PROVIDER.SetError( senderControl, message );
					IS_VALIDATED = false;
				}else{
					ERROR_PROVIDER.SetError( senderControl, null );
				}
			};
		}
		#endregion
		
		#region ValidateCombobox		
		/// <summary>
		/// Validate Combobox must have one item selected
		/// </summary>
		/// <param name="control">Combobox to validate</param>
		/// <param name="defaultIndex">True if ignor the first item</param>
		public void ValidateCombobox( ComboBox control, bool defaultIndex ){
			ValidateCombobox( control, defaultIndex, null );
		}
		
		/// <summary>
		/// Validate Combobox must have one item selected
		/// </summary>
		/// <param name="control">Combobox to validate</param>
		/// <param name="defaultIndex">True if ignor the first item</param>
		/// <param name="message">Custom message if message is not null or blank</param>
		public void ValidateCombobox( ComboBox control, bool defaultIndex, string message ){
			CONTROL_TO_VALIDATE.Add( control );
			
			control.Validating += delegate(object sender, CancelEventArgs e) {
				ComboBox senderControl = (ComboBox)sender;
				
				if( !StringLib.isValid(message) )
					message = ValidationMessage.Singleton().ValidateCombobox;
				
				if( senderControl.SelectedIndex < 0 ) {
					ERROR_PROVIDER.SetError( senderControl, message );
					IS_VALIDATED = false;
				} else if( defaultIndex && senderControl.SelectedIndex == 0 ){
					ERROR_PROVIDER.SetError( senderControl, message );
					IS_VALIDATED = false;
				}else{
					ERROR_PROVIDER.SetError( senderControl, null );
				}
			};
		}
		#endregion
		
		#region ValidateBirthday
		
		/// <summary>
		/// Validate DateTimePicker as Birthday, support mininum age and maximum age
		/// </summary>
		/// <param name="control">DateTimePicker to validate</param>
		/// <param name="minAge">Minimum age allowed</param>
		/// <param name="maxAge">Maximum age allowed</param>
		public void ValidateBirthday( DateTimePicker control, int minAge, int maxAge ){
			ValidateBirthday( control, minAge, maxAge, null );
		}
		
		/// <summary>
		/// Validate DateTimePicker as Birthday, support mininum age and maximum age
		/// </summary>
		/// <param name="control">DateTimePicker to validate</param>
		/// <param name="minAge">Minimum age allowed</param>
		/// <param name="maxAge">Maximum age allowed</param>
		/// <param name="message">Message to for both require minimum and maximum age</param>
		/// <param name="minMessage">Message for requirement of minimum age</param>
		/// <param name="maxMessage">Message for requirement of maximum age</param>
		public void ValidateBirthday( DateTimePicker control, int minAge, int maxAge, string message ){
			CONTROL_TO_VALIDATE.Add( control );
			
			control.Validating += delegate(object sender, CancelEventArgs e) {
				DateTimePicker senderControl = (DateTimePicker)sender;				
				DateTime selectedDate = senderControl.Value;				
				double currentAge = DateTime.Now.Subtract( selectedDate ).TotalDays / 365 ;
				
				if( (minAge > 0 && currentAge < minAge) ||
				   	(maxAge > 0 && currentAge > maxAge) )
				{					
										
					if( !StringLib.isValid(message) ){
						if( minAge > 0 && maxAge > 0 )
							message = ValidationMessage.Singleton().ValidateBirthday;
						else if( minAge > 0 )
							message = ValidationMessage.Singleton().ValidateBirthdayMin;
						else if( maxAge > 0 )
							message = ValidationMessage.Singleton().ValidateBirthdayMax;
					}
					
					message = message.Replace( "[MIN]", minAge+"" ).Replace( "[MAX]", maxAge+"" );
					
					ERROR_PROVIDER.SetError( senderControl, message );					
					IS_VALIDATED = false;					
				}else{
					ERROR_PROVIDER.SetError( senderControl, null );
				}
			};
		}
		
		#endregion
		
		#region ValidatePhone
		/// <summary>
		/// Validate control that store phone number (telephone and mobiphone)
		/// </summary>
		/// <param name="control">Control to validate, all controls that have Text property</param>
		/// <param name="require">True if require value otherwise require only if Text not blank</param>
		/// <param name="minLength">Minimum length requirement, -1 if not require minimum length</param>
		/// <param name="maxLength">Maximum length requirement, -1 if not require maximum length</param>
		/// <param name="isMobilephone">True if require as an mobiphone begin with 0</param>
		public void ValidatePhone( Control control, bool require, int minLength, int maxLength, bool isMobilephone){
			ValidatePhone( control, require, minLength, maxLength, isMobilephone, null );
		}
		
		/// <summary>
		/// Validate control that store phone number (telephone and mobiphone)
		/// </summary>
		/// <param name="control">Control to validate, all controls that have Text property</param>
		/// <param name="require">True if require value otherwise require only if Text not blank</param>
		/// <param name="minLength">Minimum length requirement, -1 if not require minimum length</param>
		/// <param name="maxLength">Maximum length requirement, -1 if not require maximum length</param>
		/// <param name="isMobilephone">True if require as an mobiphone begin with 0</param>
		/// <param name="message">Custom message if message is not null or blank</param>
		public void ValidatePhone( Control control, bool require, int minLength, int maxLength, bool isMobilephone, string message){
			CONTROL_TO_VALIDATE.Add( control );
			
			control.TextChanged += delegate(object sender, EventArgs e) {
				Control _control = (Control)sender;
				bool isTextBox  = FormLib.matchControlType( _control, ControlType.TextBox );
				bool isCombobox = FormLib.matchControlType( _control, ControlType.ComboBox );
				
				
				char[] chars = _control.Text.ToCharArray(); 
				for (int i = 0; i < _control.Text.Length; i++) 
				{ 
					int code; 
					code = Convert.ToInt16(chars[i]);
					if ( (code > 58 || code < 48) ) 
					{ 
						_control.Text = _control.Text.Remove(i, 1); 
						
						if( isCombobox )
							((ComboBox)_control).SelectionStart = _control.Text.Length;
						else if( isTextBox )
							((TextBox)_control).SelectionStart = _control.Text.Length;
					}
				}
			};
			
			control.Validating += delegate(object sender, CancelEventArgs e) {				
				Control senderControl = (Control)sender;				
				senderControl.Text = senderControl.Text.Trim();
				
				if( !IsValidLength( senderControl.Text, require, minLength, maxLength ) ){					
					if( !StringLib.isValid(message) )
						message = ValidationMessage.Singleton().ValidatePhone;
					
					ERROR_PROVIDER.SetError( senderControl, message );
				}else if( isMobilephone && senderControl.Text.Length > 0 && !senderControl.Text.StartsWith("0") ){
					if( !StringLib.isValid(message) )
						message = ValidationMessage.Singleton().ValidatePhoneMobile;
					
					ERROR_PROVIDER.SetError( senderControl, message );
					IS_VALIDATED = false;
				}else{
					ERROR_PROVIDER.SetError( senderControl, null );
				}
			};
		}
		#endregion
						                   
		#region ValidateText
		/// <summary>
		/// Validate Text value of any control have Text property
		/// </summary>
		/// <param name="control">Any control have Text property</param>
		/// <param name="require">True if require value otherwise require only if Text not blank</param>
		/// <param name="minLength">Minimum length requirement, -1 if not require minimum length</param>
		/// <param name="maxLength">Maximum length requirement, -1 if not require maximum length</param>
		public void ValidateText( Control control, bool require, int minLength, int maxLength ){
			ValidateText( control, require, minLength, maxLength, null );
		}
		
		/// <summary>
		/// Validate Text value of any control have Text property
		/// </summary>
		/// <param name="control">Any control have Text property</param>
		/// <param name="require">True if require value otherwise require only if Text not blank</param>
		/// <param name="minLength">Minimum length requirement, -1 if not require minimum length</param>
		/// <param name="maxLength">Maximum length requirement, -1 if not require maximum length</param>
		/// <param name="message">Custom message if message is not null or blank</param>
		public void ValidateText( Control control, bool require, int minLength, int maxLength, string message ){
			CONTROL_TO_VALIDATE.Add( control );
			
			control.Validating += delegate(object sender, CancelEventArgs e) {
				Control senderControl = (Control)sender;
				senderControl.Text = senderControl.Text.Trim();
				
				if( !IsValidLength( senderControl.Text, require, minLength, maxLength ) ){										
					if( !StringLib.isValid(message) ){
						if( minLength > 0 && maxLength > 0 )
							message = ValidationMessage.Singleton().ValidateText;
						else if( minLength > 0 )
							message = ValidationMessage.Singleton().ValidateTextMin;
						else if( maxLength > 0 )
							message = ValidationMessage.Singleton().ValidateTextMax;						
					}
					
					message = message.Replace( "[MIN]", minLength+"" ).Replace( "[MAX]", maxLength+"" );
					
					ERROR_PROVIDER.SetError( senderControl, message );
					IS_VALIDATED = false;
				}else{
					ERROR_PROVIDER.SetError( senderControl, null );
				}
			};
		}
		#endregion
		
		#region ValidateEmail
		/// <summary>
		/// Validate control to accept email address only
		/// </summary>
		/// <param name="control">Any control have Text property</param>
		public void ValidateEmail( Control control, bool require ){
			ValidateEmail( control, require, null );
		}
		
		/// <summary>
		/// Validate control to accept email address only
		/// </summary>
		/// <param name="control">Any control have Text property</param>
		/// <param name="message">Custom message if message is not null or blank</param>
		public void ValidateEmail( Control control, bool require, string message ){
			CONTROL_TO_VALIDATE.Add( control );
			
			control.Validating += delegate(object sender, CancelEventArgs e) {
				Control senderControl = (Control)sender;
				senderControl.Text = senderControl.Text.Trim();
				
				if( (require || StringLib.isValid(senderControl.Text)) && !IsEmail( senderControl.Text ) )
				{
					if( !StringLib.isValid(message) )
						message = ValidationMessage.Singleton().ValidateEmail;
					
					ERROR_PROVIDER.SetError( senderControl, message );
					IS_VALIDATED = false;
				}else{
					ERROR_PROVIDER.SetError( senderControl, null );
				}
			};
		}
				
		
		#endregion
		
		#region Common function
		public bool IsValidLength( string content, bool require, int minLength, int maxLength ){
			if( require || StringLib.isValid(content) ){
				content = content.Trim();
				if( minLength >= 0 && content.Length < minLength ){
					return false;
				}else if( maxLength >= 0 && content.Length > maxLength ){
					return false;
				}else if( minLength < 0 && maxLength < 0 && content.Length == 0 ){
					return false;
				}
				return true;
			}
			return true;
		}
		
		public bool IsEmail(string email){
			Regex emailregex = new Regex(@"[a-zA-Z0-9_\-\.]+@[a-zA-Z0-9_\-\.]+\.[a-zA-Z]{2,5}");
			Match m = emailregex.Match(email);
			return m.Success;
		}
		#endregion
	}
	
	class ValidationMessage
	{	
		private static ValidationMessage _validationmessage;		
		private static string file_config  = FileLib.getFullPath("config\\ValidationMessage.ini");
		private INISetting config;
		
		public static ValidationMessage Singleton(){			
			if( _validationmessage == null )
				_validationmessage = new ValidationMessage(file_config);
			
			return _validationmessage;
		}
			
		public ValidationMessage(string file_config){
			file_config = Path.IsPathRooted(file_config) ? file_config : FileLib.getFullPath(file_config);			
			string path = Path.GetDirectoryName(file_config);
			if( !Directory.Exists(path) ) Directory.CreateDirectory( path );
			config = new INISetting( file_config );
			LoadConfig();
			config.Save();
		}
		
		public void LoadConfig(){			
			_ValidateGroupRadioButton	= config.GetValue( "ErrorMessage", "ValidateGroupRadioButton", "Please check at least one item" );
			_ValidateGroupCheckBox		= config.GetValue( "ErrorMessage", "ValidateGroupCheckBox", "Please check at least [MIN] item" );
			_ValidateCheckedListBox		= config.GetValue( "ErrorMessage", "ValidateCheckedListBox", "Please check at least [MIN] item" );
			_ValidateListBox			= config.GetValue( "ErrorMessage", "ValidateListBox", "Please select at least [MIN] item" );
			_ValidateCombobox			= config.GetValue( "ErrorMessage", "ValidateCombobox", "Please select one item" );
			_ValidateBirthday			= config.GetValue( "ErrorMessage", "ValidateBirthday", "Your age is must between [MIN] and [MAX]" );
			_ValidateBirthdayMin		= config.GetValue( "ErrorMessage", "ValidateBirthdayMin", "Your age is must greater than [MIN]" );
			_ValidateBirthdayMax		= config.GetValue( "ErrorMessage", "ValidateBirthdayMax", "Your age is must lower than [MAX]" );
			_ValidatePhone				= config.GetValue( "ErrorMessage", "ValidatePhone", "Please enter phone number" );
			_ValidatePhoneMobile		= config.GetValue( "ErrorMessage", "ValidatePhoneMobile", "Please enter mobile phone number begin with 0" );
			_ValidateText				= config.GetValue( "ErrorMessage", "ValidateText", "Please enter at least [MIN] letters and at most [MAX] letters" );
			_ValidateTextMin			= config.GetValue( "ErrorMessage", "ValidateTextMin", "Please enter at least [MIN] letters" );
			_ValidateTextMax			= config.GetValue( "ErrorMessage", "ValidateTextMax", "Please enter at most [MAX] letters" );
			_ValidateEmail				= config.GetValue( "ErrorMessage", "ValidateEmail", "Please enter email address" );						
		}
		
		public void SaveConfig(){
			config.SetValue("ErrorMessage", "ValidateGroupRadioButton", _ValidateGroupRadioButton.ToString());
			config.SetValue("ErrorMessage", "ValidateGroupCheckBox", _ValidateGroupCheckBox.ToString());
			config.SetValue("ErrorMessage", "ValidateCheckedListBox", _ValidateCheckedListBox.ToString());
			config.SetValue("ErrorMessage", "ValidateListBox", _ValidateListBox.ToString());
			config.SetValue("ErrorMessage", "ValidateCombobox", _ValidateCombobox.ToString());
			config.SetValue("ErrorMessage", "ValidateBirthday", _ValidateBirthday.ToString());
			config.SetValue("ErrorMessage", "ValidateBirthdayMin", _ValidateBirthdayMin.ToString());
			config.SetValue("ErrorMessage", "ValidateBirthdayMax", _ValidateBirthdayMax.ToString());
			config.SetValue("ErrorMessage", "ValidatePhone", _ValidatePhone.ToString());
			config.SetValue("ErrorMessage", "ValidatePhoneMobile", _ValidatePhoneMobile.ToString());
			config.SetValue("ErrorMessage", "ValidateText", _ValidateText.ToString());
			config.SetValue("ErrorMessage", "ValidateTextMin", _ValidateTextMin.ToString());
			config.SetValue("ErrorMessage", "ValidateTextMax", _ValidateTextMax.ToString());
			config.SetValue("ErrorMessage", "ValidateEmail", _ValidateEmail.ToString());			
			config.Save();
		}
		
		private bool _AutoSave = true;
		public bool AutoSave{ get{return _AutoSave;} set{_AutoSave = value;} }
		
		private string _ValidateGroupRadioButton;
		public string ValidateGroupRadioButton{ get{return _ValidateGroupRadioButton;} set{_ValidateGroupRadioButton = value; if(AutoSave) SaveConfig(); } }

		private string _ValidateGroupCheckBox;
		public string ValidateGroupCheckBox{ get{return _ValidateGroupCheckBox;} set{_ValidateGroupCheckBox = value; if(AutoSave) SaveConfig(); } }

		private string _ValidateCheckedListBox;
		public string ValidateCheckedListBox{ get{return _ValidateCheckedListBox;} set{_ValidateCheckedListBox = value; if(AutoSave) SaveConfig(); } }

		private string _ValidateListBox;
		public string ValidateListBox{ get{return _ValidateListBox;} set{_ValidateListBox = value; if(AutoSave) SaveConfig(); } }

		private string _ValidateCombobox;
		public string ValidateCombobox{ get{return _ValidateCombobox;} set{_ValidateCombobox = value; if(AutoSave) SaveConfig(); } }

		private string _ValidateBirthday;
		public string ValidateBirthday{ get{return _ValidateBirthday;} set{_ValidateBirthday = value; if(AutoSave) SaveConfig(); } }

		private string _ValidateBirthdayMin;
		public string ValidateBirthdayMin{ get{return _ValidateBirthdayMin;} set{_ValidateBirthdayMin = value; if(AutoSave) SaveConfig(); } }

		private string _ValidateBirthdayMax;
		public string ValidateBirthdayMax{ get{return _ValidateBirthdayMax;} set{_ValidateBirthdayMax = value; if(AutoSave) SaveConfig(); } }

		private string _ValidatePhone;
		public string ValidatePhone{ get{return _ValidatePhone;} set{_ValidatePhone = value; if(AutoSave) SaveConfig(); } }

		private string _ValidatePhoneMobile;
		public string ValidatePhoneMobile{ get{return _ValidatePhoneMobile;} set{_ValidatePhoneMobile = value; if(AutoSave) SaveConfig(); } }

		private string _ValidateText;
		public string ValidateText{ get{return _ValidateText;} set{_ValidateText = value; if(AutoSave) SaveConfig(); } }

		private string _ValidateTextMin;
		public string ValidateTextMin{ get{return _ValidateTextMin;} set{_ValidateTextMin = value; if(AutoSave) SaveConfig(); } }

		private string _ValidateTextMax;
		public string ValidateTextMax{ get{return _ValidateTextMax;} set{_ValidateTextMax = value; if(AutoSave) SaveConfig(); } }

		private string _ValidateEmail;
		public string ValidateEmail{ get{return _ValidateEmail;} set{_ValidateEmail = value; if(AutoSave) SaveConfig(); } }


	}	
}
